
with ada.command_line; use ada.command_line;
with ada.text_io;      use ada.text_io;
with ada.containers;   use ada.containers;

with ada.containers.vectors;
with ada.numerics.generic_elementary_functions;

procedure leet9_palindrome is
    package foo is new ada.containers.vectors
        (index_type => positive, element_type => integer);
    use foo;

    package math is new
    ada.numerics.generic_elementary_functions(float);
    use math;

    procedure print (v : in vector) is
    begin
        for e of v loop
            put(integer'image(e));
        end loop;
        new_line;
    end;

    function is_palindrome 
        (x : in integer) return boolean is
        v : vector;
        operand : integer := x;
        i : integer := 1;
    begin
        if x < 0 then
            return false;
        end if;
        if x < 10 then
            return true;
        end if;
        while operand > 0 loop
            v.append(operand rem 10);
            operand := (operand/10);
        end loop;
        --print(v);
        --put_line(integer'image(v.element(0)));
        --put_line(integer'image(v.last_index));
        if v.first_element /= v.last_element then
            return false;
        end if;
        while i < ((v.last_index)/2) loop
            if v.element(v.first_index + i) 
            /= v.element(v.last_index - i) then
                return false;
            end if;
            i := i + 1;
        end loop;
        return true;
    end;

    function is_palindrome_no_array 
        (x : in integer)
    return boolean is
        result : boolean := false;
        sigs   : integer;
        msd : integer; -- most significant digit
        lsd : integer; --lesser significant digit
        a   : integer;
    begin
        if x < 0 then
            return false;
        end if;
        if x < 10 then
            return true;
        end if;
        if x < 100 then
            return (x mod 11 = 0);
        end if;
        sigs := integer(float'floor(math.log(float(x), 10.0))) + 1;
        for i in 0..(sigs/2) loop
            lsd := (x/(10 ** i)) rem 10;
            a   := (x/(10 ** (sigs-(i+1))));
            msd :=  a rem 10;
            if msd /= lsd then
                return false;
            end if;
        end loop;
        return true;
    end;

    procedure main (number : in integer) is 
        result : boolean := is_palindrome_no_array(number);
    begin
        if result then
            put_line(number'image & " is a palindrome.");
        else
            put_line(number'image & " is not a palindrome.");
        end if;
    end;

    procedure test is 
        factor : integer := 10101;
        number : integer;
        okay   : integer := 0;
        result : boolean;
    begin 
        for i in 1..9 loop
            number := i * factor;
            result := is_palindrome_no_array(number);
            if result then
                put_line(number'image & " is a palindrome.");
            else
                put_line(number'image & " is not a palindrome.");
            end if;
            if  result = is_palindrome(number) then
                okay := okay + 1;
            end if;
        end loop;
        put_line("both functions have the same result for " 
                 & okay'image 
                 & " of 9 cases");
    end;

    input : integer;
begin
    put_line("This is leetcode challenge #9 - palindrome numbers.");
    put_line("https://leetcode.com/problems/palindrome-number/");
    if argument_count < 1 then 
        put_line("optional: one argument to test any number");
        test;
        return;
    end if;
    begin
        input := (integer'value(argument(1)));
    exception
        -- integer'last = 2147483647
        when CONSTRAINT_ERROR => put_line("input is beyond range of integers");
    end;
    main(input);
end;
